#include <stdio.h>
#include <conio.h>
int treeToXML();

extern struct Program *prg;

struct attrs
{
    char *name;
    char *value;
};

void openTag(char *str);
void closeTag(char *str);
void fullTag(char *tag,char *str);
void attrTag(char *tag,struct attrs *curAttr,int count);
void stmtListToXML(struct StmtList *stmtList);
void stmtToXML(struct Stmt *stmt);
void exprToXML(struct NExpr *expr);
void exprListToXML(struct NExprList *expr_list);
int treeToXML();

void openTag(char *str)
{
	printf("\n<%s>", str);
}
void closeTag(char *str)
{
	printf("\n</%s>", str);
}
void fullTag(char *tag,char *str)
{
	printf("\n<%s>%s</%s>",tag, str,tag);
}
void attrOpenTag(char *tag,struct attrs *curAttr,int count)
{
    int ind=0;
    printf("\n<%s",tag);
    while(ind<count)
    {
        printf(" %s=\"%s\"",curAttr[ind].name,curAttr[ind].value);
        ind++;
    }
    printf(">");
}
void funcParamToXML(struct FuncParam *param)
{
	//openTag("FuncParam");
	//fullTag("Id", param->Id);
    struct attrs attribute[10];
    attribute[0].name="Id";
    attribute[0].value=param->Id;
    attrOpenTag("FuncParam",attribute,1);
	exprToXML(param->Val);
	closeTag("FuncParam");
}
void funcParamListToXML(struct FuncParamList *list) 
{
	struct FuncParam *item;
	openTag("FuncParamList");
	if(list != NULL)
	{
		item = list->First;

		while(item)
		{
			funcParamToXML(item);
			item=item->next;
		}
	}
	closeTag("FuncParamList");
}
void stmtListToXML(struct StmtList *stmtList)
{
    struct Stmt *stmt;
	openTag("stmtList");
    if(stmtList != NULL)
	{
		stmt = stmtList->First;

		while(stmt)
		{
			stmtToXML(stmt);
			stmt=stmt->Next;
		}
	}
	closeTag("stmtList");
}
void stmtToXML(struct Stmt *stmt)
{
	char buffer[255]={0};
    char buffer1[255]={0};
    struct attrs attribute[10];
    if (stmt!=NULL)
	{
		//openTag("Stmt");
		switch(stmt->Type)
		{
		    case ExprStmt:
			    openTag("ExprStmt");
				exprToXML(stmt->Expr);
				closeTag("ExprStmt");
			    break;
			case If:
				openTag("IfStmt");
				exprToXML(stmt->Expr);
				stmtToXML(stmt->stmt1);
				stmtToXML(stmt->stmt2);
				closeTag("IfStmt");
				break;
			case While:
				openTag("WhileStmt");
				exprToXML(stmt->Expr);
				stmtToXML(stmt->stmt1);
				closeTag("WhileStmt");
				break;
			case For:
				openTag("ForStmt");
				exprToXML(stmt->Expr);
				exprToXML(stmt->Expr2);
				exprToXML(stmt->Expr3);
				stmtToXML(stmt->stmt1);
				closeTag("ForStmt");
				break;
			case Foreach:
				openTag("ForeachStmt");
				exprToXML(stmt->Expr);
                attribute[0].name="Key";
                attribute[0].value=stmt->Id;
                attribute[1].name="Value";
                attribute[1].value=stmt->Id1;
                attrOpenTag("Variable",attribute,2);
                closeTag("Variable");
				//fullTag("Variable", stmt->Id);
				//fullTag("Variable", stmt->Id1);
				stmtToXML(stmt->stmt1);
				closeTag("ForeachStmt");
				break;
			case Print: 
				openTag("PrintStmt");
				exprListToXML(stmt->Expr_List);
				closeTag("PrintStmt");
				break;
			case Return:
				openTag("ReturnStmt");
				exprToXML(stmt->Expr);
				closeTag("ReturnStmt");
				break;
			case Echo:
				openTag("EchoStmt");
				exprListToXML(stmt->Expr_List);
				closeTag("EchoStmt");
				break;
			case ClassDecl:
				//openTag("ClassDeclStmt");
                attribute[0].name="className";
                attribute[0].value=stmt->Id;
                attribute[1].name="parentClassName";
                attribute[1].value=stmt->Parent_class_name;
                attrOpenTag("ClassDeclStmt",attribute,2);
                //fullTag("className",stmt->Id);
				//fullTag("parentClassName",stmt->Parent_class_name);
                stmtListToXML(stmt->stmtList);
				closeTag("ClassDeclStmt");
				break;	
			case MethodDecl:
				//openTag("MethodDeclStmt");
				//fullTag("isStatic", _itoa(stmt->isStatic, buffer, 10));
                //fullTag("access", _itoa(stmt->rule, buffer, 10));
                attribute[0].name="isStatic";
                attribute[0].value= _itoa(stmt->isStatic, buffer, 10);
                attribute[1].name="access";
                attribute[1].value=_itoa(stmt->rule, buffer1, 10);
                attrOpenTag("MethodDeclStmt",attribute,2);
				stmtToXML(stmt->stmt1);
				closeTag("MethodDeclStmt");
				break;
			case FieldDecl:
				//openTag("FieldDeclStmt");
				//fullTag("isStatic", _itoa(stmt->isStatic, buffer, 10));
                //fullTag("access", _itoa(stmt->rule, buffer, 10));
				//fullTag("Variable", stmt->Id);
                attribute[0].name="isStatic";
                attribute[0].value= _itoa(stmt->isStatic, buffer, 10);
                attribute[1].name="access";
                attribute[1].value=_itoa(stmt->rule, buffer1, 10);
                attribute[2].name="Variable";
                attribute[2].value=stmt->Id;
                attrOpenTag("FieldDeclStmt",attribute,3);
				exprToXML(stmt->Expr);
				closeTag("FieldDeclStmt");
				break;
			case FuncDecl:
				//openTag("FuncDeclStmt");
				//fullTag("Id", stmt->Id);
                attribute[0].name="Id";
                attribute[0].value=stmt->Id;
                attrOpenTag("FuncDeclStmt",attribute,1);
				funcParamListToXML(stmt->Param_List);
				stmtListToXML(stmt->stmtList);
				closeTag("FuncDeclStmt");
				break;
			case StmtList:
				//openTag("StmtList");
				stmtListToXML(stmt->stmtList);
				//closeTag("StmtList");
				break;
		}
		//closeTag("Stmt");
	}
}
void exprToXML(struct NExpr *expr)
{
	char buffer[255]={0};
    struct attrs attribute[10];
	if (expr)
	{
		//openTag("Expr");
		switch(expr->type)
		{
		    case Id:
                attribute[0].name="Value";
                attribute[0].value=expr->string_const;
                attrOpenTag("Id",attribute,1);
                closeTag("Id");
			    break;
            case Int:
                attribute[0].name="Value";
                attribute[0].value=_itoa(expr->int_const, buffer, 10);
                attrOpenTag("Int",attribute,1);
                closeTag("Int");
			    break;
            case Float:
                sprintf(buffer,"%g",expr->float_const);
                attribute[0].name="Value";
                attribute[0].value=buffer;
                attrOpenTag("Float",attribute,1);
                closeTag("Float");
			    break;
            case Variable:
                attribute[0].name="Value";
                attribute[0].value=expr->string_const;
                attrOpenTag("Variable",attribute,1);
                closeTag("Variable");
			    break;
            case StringConst:
                attribute[0].name="Value";
                attribute[0].value=expr->string_const;
			    attrOpenTag("StringConst",attribute,1);
                closeTag("StringConst");
			    break;
            case Minus:
			    openTag("Minus");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Minus");
			    break;
		    case Plus:
			    openTag("Plus");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Plus");
			    break;
            case Mul:
			    openTag("Mul");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Mul");
			    break;
            case Div:
			    openTag("Div");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Div");
			    break;
            case Less:
			    openTag("Less");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Less");
			    break;
            case More:
			    openTag("More");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("More");
			    break;
		    case Assign:
                openTag("Assign");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Assign");
			    break;
            case Concatenation:
                openTag("Concatenation");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Concatenation");
			    break;
            case OrOper:
                openTag("OrOper");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("OrOper");
			    break;
            case AndOper:
                openTag("AndOper");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("AndOper");
			    break;
            case Equal:
                openTag("Equal");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("Equal");
			    break;
            case NotEqual:
                openTag("NotEqual");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("NotEqual");
			    break;
            case UPlus:
                openTag("UPlus");
			    exprToXML(expr->right);
			    closeTag("UPlus");
			    break;
            case UMinus:
                openTag("UMinus");
			    exprToXML(expr->right);
			    closeTag("UMinus");
			    break;
            case Not:
                openTag("Not");
			    exprToXML(expr->right);
			    closeTag("Not");
			    break;
            case ArrayInd:
                openTag("ArrayInd");
			    exprToXML(expr->left);
			    exprToXML(expr->right);
			    closeTag("ArrayInd");
			    break;
            case ArrayE:
                openTag("ArrayE",NULL);
                exprToXML(expr->left);
                closeTag("ArrayInd");
			    break;
            case CallFunc:
                attribute[0].name="func";
                attribute[0].value=expr->string_const;
                attrOpenTag("CallFunc",attribute,1);
                exprListToXML(expr->expr_list);
			    closeTag("CallFunc");
			    break;
            case Arrow:
                openTag("Arrow");
                openTag("ArrowID");
                exprToXML(expr->right);
                closeTag("ArrowID");
                //fullTag("MethodID",expr->string_const);
                attribute[0].name="name";
                attribute[0].value=expr->string_const;
                attrOpenTag("MethodID",attribute,1);
                exprListToXML(expr->expr_list);
                closeTag("MethodID");
			    closeTag("Arrow");
			    break;
            case DoubleColon:
                attribute[0].name="class";
                attribute[0].value=expr->string_const;
                attrOpenTag("DoubleColon",attribute,1);
			    exprToXML(expr->right);
			    closeTag("DoubleColon");
			    break;
        }
        //closeTag("Expr");
    }
}
void exprListToXML(struct NExprList *expr_list)
{
    struct NExpr *expr;
	if (expr_list!=NULL)
	{
		openTag("exprList");
		expr = expr_list->first;
		while(expr)
		{
			exprToXML(expr);
			expr= expr->next;
		}
		closeTag("exprList");
	}
}
int treeToXML()
{
	if(prg != NULL)
	{
		openTag("Program");
		stmtListToXML(prg->Program_stmt_list);
		closeTag("Program");
	}
    else
    {
        printf("syntax error");
    }
    return 0;
}